#ifndef __UIDELEGATE_H__
#define __UIDELEGATE_H__

namespace duisharp {

	class DUISHARP_API CDelegateBase	 
	{
	public:
		CDelegateBase(void* pObject, void* pFn);
		CDelegateBase(const CDelegateBase& rhs);
		virtual ~CDelegateBase();
		bool Equals(const CDelegateBase& rhs) const;
		bool operator() (void* param);
		virtual CDelegateBase* Copy() const = 0; // add const for gcc

	protected:
		void* GetFn();
		void* GetObject();
		virtual bool Invoke(void* param) = 0;

	private:
		void* m_pObject;
		void* m_pFn;
	};

	class CDelegateStatic: public CDelegateBase
	{
		typedef bool (*Fn)(void*);
	public:
		CDelegateStatic(Fn pFn) : CDelegateBase(NULL, pFn) { } 
		CDelegateStatic(const CDelegateStatic& rhs) : CDelegateBase(rhs) { } 
		virtual CDelegateBase* Copy() const { return new CDelegateStatic(*this); }

	protected:
		virtual bool Invoke(void* param)
		{
			Fn pFn = (Fn)GetFn();
			return (*pFn)(param); 
		}
	};

	template <class O, class T>
	class CDelegate : public CDelegateBase
	{
		typedef bool (T::* Fn)(void*);
	public:
		CDelegate(O* pObj, Fn pFn) : CDelegateBase(pObj, &pFn), m_pFn(pFn) { }
		CDelegate(const CDelegate& rhs) : CDelegateBase(rhs) { m_pFn = rhs.m_pFn; } 
		virtual CDelegateBase* Copy() const { return new CDelegate(*this); }

	protected:
		virtual bool Invoke(void* param)
		{
			O* pObject = (O*) GetObject();
			return (pObject->*m_pFn)(param); 
		}  

	private:
		Fn m_pFn;
	};

	template <class O, class T>
	CDelegate<O, T> MakeDelegate(O* pObject, bool (T::* pFn)(void*))
	{
		return CDelegate<O, T>(pObject, pFn);
	}

	inline CDelegateStatic MakeDelegate(bool (*pFn)(void*))
	{
		return CDelegateStatic(pFn); 
	}

	class DUISHARP_API CEventSource
	{
		typedef bool (*FnType)(void*);
	public:
		~CEventSource();
		operator bool();
		void operator+= (const CDelegateBase& d); // add const for gcc
		void operator+= (FnType pFn);
		void operator-= (const CDelegateBase& d);
		void operator-= (FnType pFn);
		bool operator() (void* param);
		void Clear();

	protected:
		CStdPtrArray m_aDelegates;
	};

} // namespace duisharp

#endif // __UIDELEGATE_H__